﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Text;
using System.Xml;

namespace InfoPathHelpers.Cryptography.Authentication
{
    public static class XmlSignaturesHelper
    {
        public static void SignDocument(string inputFileName, string outputFileName, RSA RSASecurityProvider)
        {
            var Document = new XmlDocument();
            Document.PreserveWhitespace = true;
            Document.Load(inputFileName);

            var SignedXml = new SignedXml(Document)
            {
                SigningKey = RSASecurityProvider
            };

            var Reference = new Reference()
            {
                Uri = string.Empty
            };

            var SignatureTransform = new XmlDsigEnvelopedSignatureTransform();
            Reference.AddTransform(SignatureTransform);
            SignedXml.AddReference(Reference);
            SignedXml.ComputeSignature();
            var Signature = SignedXml.GetXml();
            Document.DocumentElement.AppendChild(Document.ImportNode(Signature, true));

            Document.Save(outputFileName);
        }

        public static void SignDocument(string inputFileName, RSA RSASecurityProvider)
        {
            string OutputFileName = Path.Combine(Path.GetDirectoryName(inputFileName), 
                Path.GetFileNameWithoutExtension(inputFileName) + "_Signed" + Path.GetExtension(inputFileName));

            SignDocument(inputFileName, OutputFileName, RSASecurityProvider);
        }

        public static bool ValidateSignature(string fileName, RSA RSASecurityProvider)
        {
            var Document = new XmlDocument();
            Document.PreserveWhitespace = true;
            Document.Load(fileName);

            var SignedXml = new SignedXml(Document);

            var SignatureElements = Document.GetElementsByTagName("Signature");
            if(SignatureElements.Count < 1)
            {
                throw new AuthenticationException("The document has not been signed.");
            }
            else if(SignatureElements.Count > 1)
            {
                throw new AuthenticationException("The document has multiple signatures and cannot be validated.");
            }
            SignedXml.LoadXml((XmlElement)SignatureElements[0]);
            return SignedXml.CheckSignature(RSASecurityProvider);
        }
    }
}
